// CSmalltalk.h -------------------------------------------------------------------------------//
#include <stdio.h>                                                                             //
#include <stdlib.h>                                                                            //
#include <ctype.h>                                                                             //
#include <string.h>                                                                            // 
#include <setjmp.h>                                                                            //
#include <signal.h>                                                                            //
#include <assert.h>                                                                            //
/////////////////////////////////////////////////////////////////////////////////////////////////

// {
    //{
#ifndef __cplusplus
# define true  1
# define false 0
#endif
#define ENABLE (true)
#define DISABLE (false)

#if ENABLE&&!DISABLE // CSmalltalk-parse Macro
# define registeExcept(mt)   \
(                     \
  signal(SIGABRT,mt), \
  signal(SIGFPE,mt),  \
  signal(SIGILL,mt),  \
  signal(SIGINT,mt),  \
  signal(SIGSEGV,mt), \
  signal(SIGTERM,mt), \
  true                \
)
# define nil (NULL)
# ifdef NDEBUG
#  define C57LOG(...) return 0
# else
#  define C57LOG(...) fprintf(stdout,__VA_ARGS__)
# endif
#endif

#if ENABLE&&!DISABLE // Try-pack Macro
# define TRINT(EXP) jmp_buf EXP; typedef enum
# define TRY(EXP,JBRN) int JBRN=setjmp(EXP);if(!JBRN)
# define EXPINT(JBRN) int JBRN;
# define EXPTRY(EXP,JBRN) JBRN=setjmp(EXP);if(!JBRN)
# define CATCH(JBRN,VAL) else if(JBRN==VAL)
# define THROW(EXP,VAL) (longjmp(EXP,VAL))
# define FINALLY() if(true)
#endif

#undef true
#undef false

#if !defined(__cplusplus)
  typedef enum {false, true} bool; // bool Type
#else
# define bool  bool
# define false false
# define true  true
#endif
TRINT(C57Exp) {
	NORMAL, PROGRAM_ABORT,
	UNKNOWN, NOENOUGH_MEM
} EXCEPT_VAL;
EXPINT (Exp);

#define $ (*model)
#define detect ((short)-1)
typedef char* string;
//}
    //{
typedef struct SmalltalkHandle {
	char* executes;
	char* rcode;
	short* bracks;
	short limit;
	bool enableLint;
	int btop;
} CSmalltalk;
typedef enum C57Flag {
    Native  ,  // 封装类
    Integer ,  // 整型
    String  ,  // 字符串
    Float   ,  // 浮点型
    Lambda  ,  // 闭包函数
    Alloced ,  // 分配内存
    DisabledObject
} C57Flag;
typedef struct C57Object {
    C57Flag  clflag;
	string   path;
	string   rdata;
	string   symbol;
	void(*argsplit)(char*);
} C57Object;
void exprintf(const char*fmt,...);
bool weigh(CSmalltalk*);
bool flint(void);
string malloc_string(const string);

C57Object objPool[128];
short temp,ptop=0,lmt,ftop;
char*substr(char*str,short beg,short end) {
	char*sub=(char*)malloc((end-beg+1)*sizeof(char));
	if(NULL==sub) THROW(C57Exp, NOENOUGH_MEM);
	for(short i = 0; i<(end-beg+1); i++) {
		sub[i]=str[i+beg];
	}
	if(sub[strlen(sub)-1]>=32&&sub[strlen(sub)-1]<=126); 
	else sub[strlen(sub)-1]=0;
	return sub;
}
string remove_bracks(const string str) {
	string sret=(string)malloc(sizeof(char)*strlen(str));
	if(NULL==sret) THROW(C57Exp, NOENOUGH_MEM);
	bool instr=false;
	for(short i = 0, j = 0; i < strlen(str); i++) {
		if(sret[i]=='\'') {
			sret[j++]='\'';
		} else if((sret[i]=='('||sret[i]==')')&&!instr) {
			continue;
		} else {
			sret[j++]=str[i];
		}
	}
	return sret;
}
int count5char(const string str, int ch) {
	int cnt=0, l=0;
	bool instr=false;
	for(l=0; l<strlen(str); l++) {
		if(str[l]=='\'') {
			if(!instr) instr=true;
			else if(str[l-1]!='\\') instr=false;
			else;
			continue;
		}
		if(!instr) cnt+=(str[l]==ch);
	}
	return cnt;
}
bool is_separate(const string str) {
	char alp=-1;
	for(short i = 0; i < strlen(str); i++) {
		if(isalpha(str[i])) {
		} else ;
		  if(str[i]=='-');
		  else if(str[i]=='(');
		  else if(str[i]==')');
		  else if(str[i]==' ');
		  else if(str[i]==';');
		  else if(isalpha(str[i])) {
		  } else return false;
	}
	return true;
}
    //}
/**
 * 
typedef enum C57Flag {
    Native  ,  // 封装类
    Integer ,  // 整型
    String  ,  // 字符串
    Float   ,  // 浮点型
    Lambda  ,  // 闭包函数
    Alloced ,  // 分配内存
    DisabledObject
} C57Flag;
typedef struct C57Object {
    C57Flag  clflag;
	string   path;
	string   rdata;
	string   symbol;
	void(*argsplit)(char*);
} C57Object;
*/
void nativearg(char* rt) {C57LOG("\n\033[0m[@CSmalltalk warning]\033[2m Sent a nil-message IN THE CASE OF '%s'.\033[0m\n",rt);}
void nfarg(char* rt) {C57LOG("\n\033[0m[@CSmalltalk warning]\033[2m Cannot send an message to a unknown object IN THE CASE OF '%s'.\033[0m\n",rt);}
void emptyarg(char*) {}
void CslPrint(char* rt) {
    int bg=0, ed=0;
    for(int i=0; i<strlen(rt); i++) 
        if(rt[i]=='\''&&rt[i-1]!='\\') {bg=i+1;break;}
    for(int i=bg+1; i<strlen(rt); i++) 
        if(rt[i]=='\''&&rt[i-1]!='\\') ed=i-1;
    string otp=(substr(rt,bg,ed));
    puts(otp);
    return ;
}
void FuncAdd(char* rt) {
    string argset=(string)malloc(114);
    string object=(string)malloc(114);
    string method=(string)malloc(114);
    string path=(string)malloc(114);
    string script=(string)malloc(1024);
    short bg=0, ed;
    bool instr=false;
    sscanf(rt,"%[^:]",argset);
    sscanf(argset,"%s",object);;
    sscanf(argset+strlen(object),"%s",method);
    sprintf(path,"> %s >",method);
    for(int i = 0; i<strlen(rt); i++) 
        if(rt[i]=='['&&!instr) {
            bg=i+1;
            break;
        } else if(rt[i]=='\''&&rt[i]!='\\') instr^=1;
    for(int i = strlen(rt)-1; i>=0; i--) 
        if(rt[i]==']'&&!instr) {
            ed=i-1;
            break;
        } else if(rt[i]=='\''&&rt[i]!='\\') instr^=1;
        //puts(rt);
    sprintf(script,"(:%s).",substr(rt,bg,ed));
	C57Object lambda={
	  .clflag=Lambda,
	  .path=">",
	  .rdata=script,
	  .symbol=malloc_string(method),
	  .argsplit=nativearg,
	};
	objPool[ptop++]=lambda;
	C57Object execute={
	  .clflag=Lambda,
	  .path=path,
	  .rdata=script,
	  .symbol="execute",
	  .argsplit=nativearg,
	};
	objPool[ptop++]=execute;
    return ;
}
bool flint(void) {
	ptop=0;
	C57Object Console={
	  .clflag=Native,
	  .path=">",
	  .rdata="(native)",
	  .symbol="Console",
	  .argsplit=nativearg,
	};
	objPool[ptop++]=Console;
	C57Object ConsolePrint={
	  .clflag=Native,
	  .path="> Console >",
	  .rdata="(native)",
	  .symbol="print",
	  .argsplit=CslPrint,
	};
	objPool[ptop++]=ConsolePrint;
	C57Object Functional={
	  .clflag=Native,
	  .path=">",
	  .rdata="(native)",
	  .symbol="Functional",
	  .argsplit=FuncAdd,
	};
	objPool[ptop++]=Functional;
	return true;
}
void msgparse(string pack, CSmalltalk* model) {
    string argset=(string)malloc(114);
    string object=(string)malloc(114);
    string method=(string)malloc(114);
    string path=(string)malloc(114);
    CSmalltalk vodel={.limit=detect};
    sscanf(pack+1,"%[^:]",argset);
    sscanf(argset,"%s",object);;
    sscanf(argset+strlen(object),"%s",method);
    sprintf(path,"> %s >",object);
    if(!strcmp(method,"")&&model->enableLint) nativearg(pack);
    for(int i=0; i<ptop; i++) {
        if(!strcmp(objPool[i].symbol,method)&&!strcmp(objPool[i].path,path)) {
            if(objPool[i].clflag==Native) {
                objPool[i].argsplit(pack);
                return ;
            } else {
                vodel.rcode=objPool[i].rdata, weigh(&vodel);
                return ;
            }
        } else if(!strcmp(object,"Functional")) {
            FuncAdd(pack);
        }
    }
    if(model->enableLint) nfarg(pack);
    return ;
}
bool parse(CSmalltalk* model) {
	bool instr=false, comt=false;
	short i,j,k,h,w,s,cnt0,cnt1,cnt2;
	
	if(model->limit==detect) model->limit=strlen(model->rcode);
	
	$.bracks=(short*)malloc(model->limit*sizeof(short));
	if(NULL==$.bracks) THROW(C57Exp, NOENOUGH_MEM);
	$.btop=0;
	for(i=cnt2=0; i<(model->limit); i++) {
		if(model->rcode[i]=='\''&&model->rcode[i-1]!='\\'&&!comt) instr^=1;
		if(model->rcode[i]=='\"'&&!instr) comt^=1;
		
		if(model->rcode[i]=='('&&!instr&&!cnt2&&!comt)
		 $.bracks[$.btop++]= +i;
		if(model->rcode[i]==')'&&!instr&&!cnt2&&!comt)
		 $.bracks[$.btop++]= -i;
		if(model->rcode[i]=='['&&!instr&&!comt) cnt2++;
		if(model->rcode[i]==']'&&!instr&&!comt) cnt2--;
	}
	return true;
}
bool perform(CSmalltalk*model) {
	CSmalltalk vodel={.limit=detect};
    short i,j,k,h,w,s,cnt0,cnt1,cnt2;
	$.executes=(char*)malloc(8192*sizeof(char));
	if(NULL==$.executes) THROW(C57Exp, NOENOUGH_MEM);
	static char alp='a';
	for(i=0, cnt0=0; i<($.btop); i++) {
		if($.bracks[i]<0) {
			cnt0++; // skip
			for(j=i, cnt1=0; j>=0; j--) {
				if($.bracks[j]>=0) cnt1++;
				if(cnt1==cnt0) break;
			}
			vodel.rcode=substr(model->rcode,$.bracks[j],-$.bracks[i]);
			if(!is_separate(vodel.rcode)) {
				k=i;
				if(count5char(vodel.rcode,'(')!=count5char(vodel.rcode,')')) {
					weigh(&vodel);
					while(count5char(vodel.rcode,'(')!=count5char(vodel.rcode,')')) {
						if(k==strlen(vodel.rcode)-1) break;
						if($.bracks[k]>=0);
						vodel.rcode=substr(model->rcode,$.bracks[j],-$.bracks[k]);
						k++;	
					}
					--k;
				}
			//	printf("  #%c as ({%s} execute);\n",alp,remove_bracks(vodel.rcode));
			    msgparse(remove_bracks(vodel.rcode),model);
				alp++;
				model->rcode[$.bracks[j]+1]=alp-1,
				model->rcode[$.bracks[j]]='(',
				model->rcode[-$.bracks[k]]=')';
				for(w=$.bracks[j]+2; w<-$.bracks[k]; w++) model->rcode[w]='-';
			}
		}
	}
	free($.executes);
	return true;
}
bool weigh(CSmalltalk*model) {
    parse(model), perform(model);
    return true;
}
bool witlaunch(CSmalltalk*model,CSmalltalk*vodel) {
    int w, result=flint();
    result+=parse(model);
    result+=perform(model);
	for(w=0;w<5;w++) if(!strcmp(objPool[w].symbol,"main")) break;
	vodel->rcode=malloc_string(objPool[w].rdata);
	result+=flint();
    result+=parse(vodel);
    result+=perform(vodel);
    return result==6;
}
string malloc_string(const string str) {
	string sret=(string)malloc(sizeof(char)*strlen(str+1));
	if(NULL==sret) THROW(C57Exp, NOENOUGH_MEM);
	strcpy(sret,str);
	return sret;
}
void caught(int code) {
    if(code^SIGINT&&code^SIGTERM) {
        C57LOG("[@CSmalltalk logout] Caught a FATAL-ERROR: %s\r\n",strerror(code));
        exit(code);
    } else THROW(C57Exp,PROGRAM_ABORT);
    return ;
}
#undef $
//}

// CSmalltalk.C
int main(int argc, const char**argv) {
    registeExcept(caught);
	EXPTRY(C57Exp,Exp) {
		C57LOG("[@CSmalltalk launch] CSmalltalk Launch.%s","\r\n");
		CSmalltalk c57vm = {
		  .rcode=malloc_string("\
(Functional main:  [\
  (Wing constructBy: 'furry\\'s fur' | '18cm*');\
  (Bird build: class | happy: (Console print: 'Merro(OwO) 0xCAFFCA75'));\
])."),
		  .limit=detect,
		}, c57ex={.limit=detect};
	//	if(argc>1&&!strcmp(argv[1], "feeding~")) {
	    do {
			printf("\033[7m\n      /\\ __/\\      \n");
			printf("🌺   / _   _   \\    \n");
			printf("\033[4m(ξ)|____∇__\033[101m“\033[0m\033[4m\033[7m__(_)  \n");
			printf("    CSmalltalk     \n\n\033[0m", 0xCAFFCA75);
		} while(0);
	  assert(
		flint() & witlaunch(&c57vm, &c57ex)   );
		C57LOG("\r\n");
		for(int i=0;i<5; i++) printf("%-12s%.24s... %-10s %d\n",objPool[i].symbol, objPool[i].rdata, objPool[i].path, objPool[i].clflag);
		C57LOG("[@CSmalltalk logout] EXIT 0.%s","\r\n");
		return 0;
	} CATCH(Exp,NOENOUGH_MEM) {
		C57LOG("[@CSmalltalk logout] No enough memory.%s","\r\n");
	} CATCH(Exp,UNKNOWN) {
		C57LOG("[@CSmalltalk logout] For some unkown reason(s), the program had been logout.%s","\r\n");
	} CATCH(Exp,PROGRAM_ABORT) {
		C57LOG("[@CSmalltalk logout] Program abort.%s","\r\n");
	} FINALLY() {
		C57LOG("[@CSmalltalk logout] EXIT -1.%s","\r\n");
	}
	return -1;
}
